package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.utils;


import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

/**
 * OSS文件上传类
 *
 * @author YangYing
 * @date 2018/9/27 9:12
 */
public class OSS {
    /**
     * OSS地域节点
     */
    private static String endpoint = null;
    /**
     * OSS的AccessKey ID
     */
    private static String keyId = null;
    /**
     * OSS的AccessKey Secret
     */
    private static String keySecret = null;
    /**
     * OSS的Bucket名称
     */
    private static String bucketName = null;
    /**
     * OSS文件访问地址的过期时间 单位为天 默认为20年
     */
    private static Integer expiration = 365 * 20;
    /**
     * OSS的文件存储目录 默认为根目录
     */
    private static String folder = "test";

    private static Logger LOGGER = LoggerFactory.getLogger(OSS.class);

    public static void setup(String endpoint, String keyId, String keySecret, String bucketName) {
        OSS.endpoint = endpoint;
        OSS.keyId = keyId;
        OSS.keySecret = keySecret;
        OSS.bucketName = bucketName;
    }

    public static void setup(String endpoint, String keyId, String keySecret, String bucketName, Integer expiration, String folder) {
        OSS.endpoint = endpoint;
        OSS.keyId = keyId;
        OSS.keySecret = keySecret;
        OSS.bucketName = bucketName;
        OSS.expiration = expiration;
        OSS.folder = folder;
    }

    /**
     * 上传文件至OSS
     *
     * @param fileList List<MultipartFile>
     * @return List<String> 文件的访问地址
     */
    public static String uploadFiles2OSS(List<MultipartFile> fileList) throws Exception {
        String fileName = "";
        try {
            if (fileList.size() > 0) {
                for (int i = 0; i < fileList.size(); i++) {
                    MultipartFile file = fileList.get(i);
                    String originalFilename = file.getOriginalFilename();
                    if (!file.isEmpty()) {
                        byte[] bytes = file.getBytes();
                        fileName = uploadBytes(bytes, originalFilename);
                    }
                }
            } else {
                LOGGER.error("上传的文件为空!");
                throw new Exception("上传的文件为空!");
            }
        } catch (Exception e) {
            LOGGER.error("文件上传失败: ", e);
            throw new Exception(e);
        }
        LOGGER.info("文件上传成功!");
        return fileName;
    }

    /**
     * 上传byte[]到OSS
     *
     * @param b 字节数组
     * @return String 文件的url
     */
    private static String uploadBytes(byte[] b, String fileName) {
        String ossFileName = UUID.randomUUID().toString() + "_" + fileName;
        Long fileSize = (long) b.length;
        // 创建上传Object的Metadata
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(fileSize);
        // 指定该Object被下载时的网页的缓存行为
        metadata.setCacheControl("no-cache");
        // 指定该Object下设置Header
        metadata.setHeader("Pragma", "no-cache");
        // 指定该Object被下载时的内容编码格式
        metadata.setContentEncoding("utf-8");
        // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
        // 如果没有扩展名则填默认值application/octet-stream
        metadata.setContentType(getContentType(fileName));
        // 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
        metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
        OSSClient ossClient = getOSSClient();
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
        ossFileName = folder + "/" + df.format(new Date()) + "/" + ossFileName;
        PutObjectResult putResult = ossClient.putObject(bucketName, ossFileName, new ByteArrayInputStream(b));
        ossClient.shutdown();
        return ossFileName;
    }

    /**
     * 获取阿里云OSS客户端对象
     *
     * @return ossClient
     */
    private static OSSClient getOSSClient() {
        return new OSSClient(endpoint, keyId, keySecret);
    }


    /**
     * 获取文件访问路径
     *
     * @param fileName 文件在OSS上面存储的名称
     * @return String
     */
    public static String getUrl(String fileName) {
        // 设置URL过期时间为10年 3600l* 1000*24*365*10
        Date expirationTime = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * expiration);
        // 生成URL
        OSSClient ossClient = getOSSClient();
        URL url = ossClient.generatePresignedUrl(bucketName, fileName, expirationTime);
        if (url != null) {
            LOGGER.info("文件上传至:" + url);
            ossClient.shutdown();
            return url.toString();
        }
        LOGGER.error("获取文件路径出错");
        return "获文件路径出错";
    }

    /**
     * 通过文件名判断并获取文件的contentType
     *
     * @param fileName 文件名
     * @return 文件的contentType
     */
    private static String getContentType(String fileName) {
        // 文件的后缀名
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        if (".bmp".equalsIgnoreCase(fileExtension)) {
            return "image/bmp";
        }
        if (".gif".equalsIgnoreCase(fileExtension)) {
            return "image/gif";
        }
        if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
                || ".png".equalsIgnoreCase(fileExtension)) {
            return "image/jpeg";
        }
        if (".html".equalsIgnoreCase(fileExtension)) {
            return "text/html";
        }
        if (".txt".equalsIgnoreCase(fileExtension)) {
            return "text/plain";
        }
        if (".vsd".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.visio";
        }
        if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.ms-powerpoint";
        }
        if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
            return "application/msword";
        }
        if (".xml".equalsIgnoreCase(fileExtension)) {
            return "text/xml";
        }
        if (".mp4".equalsIgnoreCase(fileExtension)) {
            return "video/mp4";
        }
        // 默认返回类型
        return "image/jpeg";
    }

    /**
     * oss文件下载
     */
    public static String downloadFiles(String objectName) throws Exception {
        OSSClient ossClient = getOSSClient();
        ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File("/Users/huheng/工作目录/测试/" + objectName));
        return null;
    }

    public static void downloadFile(String filePath) {
        OSSClient ossClient = getOSSClient();
        OSSObject ossObject = ossClient.getObject(bucketName, filePath);
        InputStream inputStream = ossObject.getObjectContent();
        Long byteLength = ossObject.getObjectMetadata().getContentLength();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        int index = filePath.lastIndexOf("/");
        String fileName = URLEncoder.encode(filePath.substring(index + 1));
        response.reset();
        response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
        response.addHeader("Content-Length", "" + byteLength);
        response.setContentType("application/octet-stream;charset=UTF-8");
        try {
            ServletOutputStream out = response.getOutputStream();
            if (byteLength < Integer.MAX_VALUE) {
                byte[] buf = new byte[1024];
                for (int n = 0; n != -1; ) {
                    n = inputStream.read(buf, 0, buf.length);
                    if (n != -1) {
                        out.write(buf, 0, n);
                    }
                }
            } else {
                throw new RuntimeException("file too large");
            }
            inputStream.close();
            out.flush();
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
